﻿using UnityEngine;
using SocketWeaver.FixedMath;

namespace SocketWeaver.FPhysics2D
{
    [RequireComponent(typeof(FTransform))]
    [ExecuteInEditMode]
    public class FPolygonCollider2D : FCollider2D
    {
        Sprite sprite;

        public FVector2[] convexVerts;
        public int convexVertsCount;

        [SerializeField]
        FVector2 _size = FVector2.one;
        public FVector2 size
        {
            get
            {
                return _size;
            }
        }

        public void UpdateShape(FVector2 size)
        {
            _size = size;
            UpdateShape(_root);
        }

        public int limit = 8;

        void Reset()
        {
            BuildConvexData();
        }

        public void BuildConvexData()
        {
            SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
            if (spriteRenderer != null)
            {
                sprite = spriteRenderer.sprite;
                if (sprite != null)
                {
                    ConvexHull2D(sprite);
                }
            }
        }

        void ConvexHull2D(Sprite sprite)
        {
            Vector2[] verts = sprite.vertices;
            int vertsCount = verts.Length;

            FVector2[] fixedVerts = new FVector2[vertsCount];
            for (int i = 0; i < vertsCount; i++)
            {
                fixedVerts[i] = (FVector2)verts[i];
            }

            FVector2[] vertsOut = new FVector2[vertsCount];
            int count = FPhysics2D.ConvexHull2D(fixedVerts, vertsCount, vertsOut, limit);

            convexVerts = new FVector2[count];
            for (int i = 0; i < count; i++)
            {
                convexVerts[i] = vertsOut[i];
            }

            convexVertsCount = count;
        }

        void OnDrawGizmosSelected()
        {
            Gizmos.color = FPhysicsGizmoDraw.ColliderOutlineColor;
            for(int i = 0; i < convexVertsCount; i++)
            {
                int i1 = i;
                int i2 = i == (convexVertsCount - 1) ? 0 : i1 + 1;
                Vector2 vert1 = (Vector2)convexVerts[i1];
                Vector2 vert2 = (Vector2)convexVerts[i2];

                Gizmos.DrawLine(transform.TransformPoint(vert1), transform.TransformPoint(vert2));
            }
            //foreach (FVector2 v in convexVerts)
            //{
            //    Vector2 vert = (Vector2)v;
            //    Gizmos.DrawWireSphere(transform.TransformPoint(vert), 0.1f);
            //}
        }

        FVector2 CalculateSize()
        {
            FVector2 s = _size * (FVector2)colliderScale;
            return s;
        }

        protected override void UpdateShape(GameObject root)
        {
            FVector2 s = CalculateSize();

            if (s != FVector2.zero)
            {
                FVector2[] scaled = new FVector2[convexVertsCount];

                for (int i = 0; i < convexVertsCount; i++)
                {
                    scaled[i] = convexVerts[i] * s;
                }

                FFloat angle = FFloat.zero;
                FVector2 center = FVector2.zero;

                if (gameObject != root)
                {
                    angle = FFloat.DegToRad(fTransform.localEulerAngles.z);
                    center = (FVector2)fTransform.localPosition;
                }

                FPhysics2D.UpdatePolygon(_shape, _fixture, scaled, convexVertsCount, center, angle);
            }
        }

        internal override FPhysicsShape2D CreateShape(GameObject root)
        {
            FVector2 s = CalculateSize();

            if (s != FVector2.zero)
            {

                FFloat angle = FFloat.zero;
                FVector2 center = FVector2.zero;

                if (gameObject != root)
                {
                    angle = FFloat.DegToRad(fTransform.localEulerAngles.z);
                    center = (FVector2)fTransform.localPosition;
                }

                if (s == FVector2.one)
                {
                    return FPhysics2D.CreatePolygon(convexVerts, convexVertsCount, center, angle);
                }
                else
                {
                    FVector2[] scaled = new FVector2[convexVertsCount];

                    for (int i = 0; i < convexVertsCount; i++)
                    {
                        scaled[i] = convexVerts[i] * s;
                    }

                    return FPhysics2D.CreatePolygon(scaled, convexVertsCount, center, angle);
                }
            }
            else
            {
                return null;
            }
        }
    }
}